classdef LoggingService < handle
    % LOGGINGSERVICE 日志记录服务
    % 基于DO-178规则第4条（架构分离原则）设计
    % 负责日志的记录、管理和归档
    %
    % 功能：
    %   - 日志记录（支持不同级别）
    %   - 日志文件管理（自动创建、归档）
    %   - 与MessageService配合使用
    %   - 支持DEV和CI环境
    %
    % 设计原则：
    %   - 业务逻辑在Service中，GUI只负责调用
    %   - 明确的日志级别，便于过滤和分析
    %   - 支持DO-178的可追溯性要求
    %
    % 使用示例：
    %   % 方式1：单例模式（推荐）
    %   logger = LoggingService.getInstance();
    %   logger.log('操作成功', 'info');
    %   
    %   % 方式2：创建实例
    %   logger = LoggingService();
    %   logger.logInfo('信息消息');
    %   logger.logWarning('警告消息');
    %   logger.logError('错误消息');
    %   
    %   % 方式3：配合MessageService使用
    %   msgObj = MessageService.create('操作成功', 'Level', 'success', 'Timestamp', true);
    %   logger.logMessage(msgObj);
    %
    % 作者: MBD Platform Team
    % 日期: 2025-10-14
    % 遵循DO-178标准
    
    properties (Access = private)
        logDir              % 日志目录
        currentLogFile      % 当前日志文件路径
        environment         % 运行环境：'DEV' 或 'CI'
        enableLogging       % 是否启用日志
        maxLogFileSize      % 最大日志文件大小（字节）
        maxLogFiles         % 最大日志文件数量
    end
    
    properties (Constant)
        DEFAULT_MAX_FILE_SIZE = 10 * 1024 * 1024;  % 10MB
        DEFAULT_MAX_FILES = 10;                     % 保留10个日志文件
    end
    
    methods (Access = private)
        function obj = LoggingService(varargin)
            % 私有构造函数（单例模式）
            % 
            % 输入参数:
            %   varargin - 可选参数（Name-Value pairs）
            %     'Environment' - 运行环境（'DEV'/'CI'，默认：'DEV'）
            %     'EnableLogging' - 是否启用日志（默认：true）
            %     'MaxFileSize' - 最大文件大小（默认：10MB）
            %     'MaxFiles' - 最大文件数量（默认：10）
            
            % 参数解析
            p = inputParser;
            addParameter(p, 'Environment', 'DEV', @(x) ismember(x, {'DEV', 'CI'}));
            addParameter(p, 'EnableLogging', true, @islogical);
            addParameter(p, 'MaxFileSize', obj.DEFAULT_MAX_FILE_SIZE, @isnumeric);
            addParameter(p, 'MaxFiles', obj.DEFAULT_MAX_FILES, @isnumeric);
            parse(p, varargin{:});
            
            obj.environment = p.Results.Environment;
            obj.enableLogging = p.Results.EnableLogging;
            obj.maxLogFileSize = p.Results.MaxFileSize;
            obj.maxLogFiles = p.Results.MaxFiles;
            
            % 初始化日志目录
            obj.initializeLogDirectory();
        end
    end
    
    methods (Static, Access = public)
        function obj = getInstance(varargin)
            % GETINSTANCE 获取LoggingService单例
            % 
            % 输入参数:
            %   varargin - 可选参数（仅首次调用有效）
            %
            % 输出参数:
            %   obj - LoggingService实例
            
            persistent instance;
            if isempty(instance) || ~isvalid(instance)
                instance = LoggingService(varargin{:});
            end
            obj = instance;
        end
        
        function resetInstance()
            % RESETINSTANCE 重置单例（主要用于测试）
            LoggingService.getInstance();  % 确保实例存在
            % 清空persistent变量需要clear
        end
    end
    
    methods (Access = public)
        
        %% ==================== 主要日志方法 ====================
        
        function log(obj, message, level)
            % LOG 记录日志
            % 
            % 输入参数:
            %   message - 日志消息（字符串）
            %   level - 日志级别（'info'/'warning'/'error'/'success'，可选）
            
            if ~obj.enableLogging
                return;
            end
            
            if nargin < 3
                level = 'info';
            end
            
            % 格式化日志消息
            timestamp = char(datetime('now'), 'yyyy-MM-dd HH:mm:ss');
            logEntry = sprintf('[%s] [%s] %s', timestamp, upper(level), message);
            
            % 写入日志文件
            obj.writeToFile(logEntry);
        end
        
        function logInfo(obj, message)
            % LOGINFO 记录信息级别日志
            obj.log(message, 'info');
        end
        
        function logWarning(obj, message)
            % LOGWARNING 记录警告级别日志
            obj.log(message, 'warning');
        end
        
        function logError(obj, message)
            % LOGERROR 记录错误级别日志
            obj.log(message, 'error');
        end
        
        function logSuccess(obj, message)
            % LOGSUCCESS 记录成功级别日志
            obj.log(message, 'success');
        end
        
        function logMessage(obj, msgObj)
            % LOGMESSAGE 记录MessageService创建的消息对象
            % 
            % 输入参数:
            %   msgObj - MessageService.create()返回的消息结构
            %
            % 示例：
            %   msgObj = MessageService.create('操作成功', 'Level', 'success');
            %   logger.logMessage(msgObj);
            
            if ~obj.enableLogging
                return;
            end
            
            if isstruct(msgObj) && isfield(msgObj, 'text') && isfield(msgObj, 'level')
                obj.log(msgObj.text, msgObj.level);
            else
                % 如果不是标准的msgObj，尝试作为字符串记录
                obj.log(char(msgObj), 'info');
            end
        end
        
        %% ==================== 日志文件管理 ====================
        
        function path = getCurrentLogFile(obj)
            % GETCURRENTLOGFILE 获取当前日志文件路径
            path = obj.currentLogFile;
        end
        
        function archiveOldLogs(obj)
            % ARCHIVEOLDLOGS 归档旧日志文件
            % 根据maxLogFiles设置，删除过期的日志文件
            
            if ~exist(obj.logDir, 'dir')
                return;
            end
            
            % 获取所有日志文件
            logFiles = dir(fullfile(obj.logDir, 'logFile_*.log'));
            
            if length(logFiles) <= obj.maxLogFiles
                return;
            end
            
            % 按修改时间排序
            [~, idx] = sort([logFiles.datenum], 'descend');
            logFiles = logFiles(idx);
            
            % 删除超出数量的旧文件
            for i = (obj.maxLogFiles + 1):length(logFiles)
                try
                    delete(fullfile(obj.logDir, logFiles(i).name));
                catch
                    % 删除失败，忽略
                end
            end
        end
        
        function clearLogs(obj)
            % CLEARLOGS 清空所有日志文件
            
            if ~exist(obj.logDir, 'dir')
                return;
            end
            
            logFiles = dir(fullfile(obj.logDir, 'logFile_*.log'));
            for i = 1:length(logFiles)
                try
                    delete(fullfile(obj.logDir, logFiles(i).name));
                catch
                    % 删除失败，忽略
                end
            end
            
            % 重新初始化日志文件
            obj.initializeLogDirectory();
        end
        
        function setEnableLogging(obj, enable)
            % SETENABLELOGGING 启用/禁用日志记录
            % 
            % 输入参数:
            %   enable - 是否启用（boolean）
            
            obj.enableLogging = enable;
        end
        
        function enabled = isLoggingEnabled(obj)
            % ISLOGGINGENABLED 检查日志是否启用
            enabled = obj.enableLogging;
        end
        
    end
    
    methods (Access = private)
        
        function initializeLogDirectory(obj)
            % 初始化日志目录和当前日志文件
            
            try
                % 使用ProjectPathManager获取work目录
                workDir = ProjectPathManager.getDirPath('work');
                obj.logDir = fullfile(workDir, 'logs');
                
                % 创建日志目录
                if ~exist(obj.logDir, 'dir')
                    mkdir(obj.logDir);
                end
                
                % 生成当前日志文件名
                logFileName = sprintf('logFile_%s.log', datestr(now, 'yymmddHHMM'));
                obj.currentLogFile = fullfile(obj.logDir, logFileName);
                
                % 归档旧日志
                obj.archiveOldLogs();
                
            catch ME
                warning('LoggingService:InitFailed', ...
                    '日志目录初始化失败: %s', ME.message);
                obj.enableLogging = false;
            end
        end
        
        function writeToFile(obj, logEntry)
            % 写入日志到文件
            
            try
                % 检查日志目录是否存在，不存在则创建（规则第2条：明确处理错误）
                if ~exist(obj.logDir, 'dir')
                    mkdir(obj.logDir);
                end
                
                % 检查文件大小，如果超过限制则创建新文件
                if exist(obj.currentLogFile, 'file')
                    fileInfo = dir(obj.currentLogFile);
                    if fileInfo.bytes > obj.maxLogFileSize
                        obj.initializeLogDirectory();  % 创建新日志文件
                    end
                end
                
                % 写入日志
                fid = fopen(obj.currentLogFile, 'a+');
                if fid > 0
                    fprintf(fid, '%s\n', logEntry);
                    fclose(fid);
                else
                    warning('LoggingService:FileOpenFailed', ...
                        '无法打开日志文件: %s', obj.currentLogFile);
                end
                
            catch ME
                warning('LoggingService:WriteFailed', ...
                    '日志写入失败: %s', ME.message);
            end
        end
        
    end
end

